/**
 *  @file  Thread.h version 1.0 2007-11-20 $
 *  @brief Define wapper class for threads.
 *  Copyright (c) 2008 by @author Zhao Jun <zjwaszx@gmail.com>
 */

#ifndef __THREAD_H__
#define __THREAD_H__

#include <vector>
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN		// to remove the unused content from Windows.h
#include <Windows.h>
#include <Process.h>
#else
#include <pthread.h>
#endif

namespace vs {

/**
@brief Namespace for thread classes.
*/
namespace thread {

#ifdef WIN32
/// Define the thread handle.
typedef HANDLE THREAD_HANDLE;

/// Define the thread id.
typedef unsigned int THREAD_ID;
#else
typedef pthread_t THREAD_HANDLE;
typedef unsigned long THREAD_ID;
#endif


/// Wrapper class for windows event.
class ThreadEvent
{
	/// Define the event handle.
	typedef HANDLE THREAD_EVENT;
public:
	/// Constructor.
	ThreadEvent( void ) 
	{
		event_ = CreateEvent(NULL, FALSE, FALSE, NULL); // need mannual reset.
	}
	
	/// Destructor.
	~ThreadEvent( void ) {}


	/// Set the event, make the Wait() calling can return.
	void Set()
	{
		SetEvent(event_);
	}
	
	/// Set the event, make the Wait() calling can not return.
	void ResetEvent()
	{
		::ResetEvent(event_);
	}
	
	/// Wait the event, blocking or timeout.
	UINT32 Wait(int milliSecond = INFINITE)
	{
		WaitForSingleObject(event_, milliSecond);
		return 0;
	}

private:
	/// Underlying event.
	THREAD_EVENT event_;
};


/// Null mutex, used for single thread, runtime overheading is zero.
class NullMutex
{
public:
	NullMutex( void ) {}
	~NullMutex( void ) {}

	///@{
	/// Null operations.
	int lock( void ) { return 0; }
	int unlock( void ) { return 0; }
	///@}
};


/// Multi-threads mutex.
class ThreadMutex
{
public:
	/// Constructor, create the mutex.
	ThreadMutex( void )
	{
#ifdef WIN32
		InitializeCriticalSection(&mutex_); 
#else
		pthread_mutex_init(&mutex_, NULL);
#endif
	}

	/// Destructor, destroy the mutex.
	~ThreadMutex( void )
	{
#ifdef WIN32
		DeleteCriticalSection(&mutex_); 
#else
		pthread_mutex_destroy(&mutex_);
#endif
	}

	/// Lock the mutex.
	int lock( void )
	{
#ifdef WIN32
		EnterCriticalSection(&mutex_);
		return 0;
#else
		return pthread_mutex_lock(&mutex_);
#endif	
	}

	/// Unlock the mutex.
	int unlock( void )
	{
#ifdef WIN32
		LeaveCriticalSection(&mutex_);
		return 0;
#else
		return pthread_mutex_unlock(&mutex_);
#endif
	}

private:
#ifdef WIN32
	CRITICAL_SECTION mutex_;
#else
	pthread_mutex_t mutex_;
#endif
};


/// Mutex guard, combined mutex with scope, auto lock and unlock.
template<typename MUTEX>
class MutexGuard
{
public:
	/// Constructor, lock the mutex.
	MutexGuard( MUTEX &mutex )
		: mutex_(mutex)
	{
		mutex_.lock();
	}

	/// Destructor, unlock the mutex.
	~MutexGuard( void )
	{
		mutex_.unlock();
	}

private:
	MUTEX &mutex_;
};


/** 
 @brief The interface for a runnable object, the base class for threads.
 */
class Runnable 
{
public:
	/** @brief The interface for a runnable object, must be implemented by derived classes.
	
	The Runnable class can be used as a composer pattern.
	*/
	virtual void run( void ) = 0;
	
	/// Virtual destructor.
	virtual ~Runnable( void ) {}
};


/** 
 @brief Wrapper class for threads.

 Derived from Runnable, and provide some interfaces for a thread operations. This class provides a default 
 implentation for run(), can be used as base class for threads.
 */
class Thread : public Runnable 
{
	/// Wrapper class for underlying thread informations in different platforms.
	class ThreadInfo
	{
		friend class Thread;
	public:
		ThreadInfo( void )
			: handle_(0), id_(0) {}

		THREAD_HANDLE handle_;
		THREAD_ID id_;

		void clear( void )
		{
			handle_ = 0;
			id_ = 0;
		}
	};

public:
	/// Constructor.
	explicit Thread( Runnable* target = 0, bool delete_target = true, bool paused = false );
	
	/// Virtual destructor.
	virtual ~Thread( void );
	
	/// Start a thread.
	void start( void );
	
	/// Wait a thread to end.
	void join( void );
	
	/// Terminate a thread.
	void terminate( void );

	/// Set the pause state.
	void pause(bool paused) { paused_ = paused; }
	
	/// Get the pause state.
	bool pause() { return paused_; }

	/// Get the thread handle.
	THREAD_HANDLE handle( void ) { return threadInfo_.handle_; }
	
	/// Get the thread id.
	THREAD_ID id( void ) { return threadInfo_.id_; }
	
	/// Default implementation for this interface.
	virtual void run( void ) {}
	
private:
	static unsigned __stdcall threadProc( void* param );
private:
	Runnable* target_;
	ThreadInfo threadInfo_;
	bool delete_target_;
	bool paused_;
};


#ifdef WIN32

inline
Thread::Thread( Runnable* target, bool delete_target, bool paused )
	:target_(target), delete_target_(delete_target), paused_(paused)
{
}

inline
Thread::~Thread( void )
{
	if (threadInfo_.handle_ != 0)
		CloseHandle(threadInfo_.handle_);
	if ((target_ != 0) && delete_target_)
		delete target_;
	threadInfo_.clear();
}

inline
void Thread::start( void ) 
{
	if (threadInfo_.handle_ != 0)
		return;
	threadInfo_.handle_ = reinterpret_cast<HANDLE>( _beginthreadex(0, 0, threadProc, this, 0, &threadInfo_.id_) );
}

inline
void Thread::join( void ) 
{
	if (threadInfo_.handle_ != 0) 
	{
		WaitForSingleObject(threadInfo_.handle_, INFINITE);
		CloseHandle(threadInfo_.handle_);
		threadInfo_.clear();
	}
}

inline
void Thread::terminate( void )
{
	TerminateThread( (HANDLE)threadInfo_.handle_, 0 );
	CloseHandle(threadInfo_.handle_);
	threadInfo_.clear();
}

inline
unsigned __stdcall Thread::threadProc( void* param ) 
{
	Thread* thisThread = static_cast<Thread*>(param);
	if (thisThread->target_ != 0)
		thisThread->target_->run();
	else
		thisThread->run();
	return 0;
}


#else


inline
Thread::Thread( Runnable* target, bool delete_target )
	:target_(target), delete_target_(delete_target)
{
}

inline
Thread::~Thread( void )
{
	if ((target_ != 0) && delete_target_)
		delete target_;
	threadInfo_.clear();
}

inline
void Thread::start( void ) 
{
	if (threadInfo_.handle_ != 0)
		return;
	pthread_create(&threadInfo_.id_, NULL, ServiceEntryFunction, this);
	// note : for pthread, no handle concept, so just set it to its thread id.
	threadInfo_.handle_ = threadInfo_.id_;
}

inline
void Thread::join( void ) 
{
	if (threadInfo_.id_ != 0) 
	{
		pthread_join(threadInfo_.id_);
		threadInfo_.clear();
	}
}

inline
void Thread::terminate( void )
{
	pthread_cancel( threadInfo_.id_ );
	threadInfo_.clear();
}

inline
unsigned __stdcall Thread::threadProc( void* param ) 
{
	Thread* thisThread = static_cast<Thread*>(param);
	if (thisThread->target_ != 0)
		thisThread->target_->run();
	else
		thisThread->run();
	return 0;
}

#endif


/// This class manages a group of threads.
class ThreadManager
{
public:
	/// The group type definition for thread.
	typedef std::vector<Thread*> THREAD_ARRAY;

	/// Constructor.
	ThreadManager( void ) 
		: target_(0), delete_target_(true)
	{}

	/// Destructor.
	~ThreadManager( void )
	{
		clear();
		
		if ((target_ != 0) && delete_target_)
			delete target_;
	}
	
	/// Create a group of threads.
	void create( int count, Runnable *target = 0, bool delete_target = true )
	{
		if (target_ != 0)
			return;
		target_ = target;
		delete_target_ = delete_target;

		for ( int i = 0; i < count; i++ )
		{
			Thread * th_ptr = new Thread(target, false);
			threads_.push_back(th_ptr);
		}
	}

	/// Start the group of threads.
	void start( void )
	{
		for ( THREAD_ARRAY::iterator it = threads_.begin(); it != threads_.end(); it++ )
		{
			(*it)->start();
		}
	}

	/// Terminate the group of threads.
	void terminate( void )
	{
		for ( THREAD_ARRAY::iterator it = threads_.begin(); it != threads_.end(); it++ )
		{
			(*it)->terminate();
		}
		clear();
	}

	/// Wait the group of threads to end.
	void join( void )
	{
#ifdef WIN32
		int count = threads_.size();
		THREAD_HANDLE *thread_handles = new THREAD_HANDLE[count];
		for ( int i = 0; i < count; ++i )
		{
			thread_handles[i] = threads_[i]->handle();
		}

		WaitForMultipleObjects( count, thread_handles, TRUE, INFINITE );
		delete [] thread_handles;
#else
		int count = threads_.size();
		for ( int i = 0; i < count; ++i )
		{
			pthread_join(threads_[i]->handle());
		}
#endif
		clear();
	}
	
	/// Clear the group of threads.
	void clear( void )
	{
		for ( THREAD_ARRAY::iterator it = threads_.begin(); it != threads_.end(); it++ )
		{
			delete *it;
		}

		threads_.clear();
	}

private:
	Runnable *target_;
	bool delete_target_;
	THREAD_ARRAY threads_;
	ThreadManager( ThreadManager const & );
	ThreadManager & operator = ( ThreadManager const & );
};

} // namespace thread
} // namespace vs

#endif // __THREAD_H__
